﻿   
    module Math  
    
    
    open Microsoft.Xna.Framework
    open Microsoft.FSharp.Core.LanguagePrimitives 


        type Vector3< [< Measure >] 'u > =
            struct
                val mutable internal vector : Microsoft.Xna.Framework.Vector3

                member this.X 
                  with get() = (this.vector.X |> Float32WithMeasure) : float32<'u>
                  and set (v:float32<'u>) = this.vector.X <- v |> float32
                member this.Y 
                  with get() = (this.vector.Y |> Float32WithMeasure) : float32<'u>
                  and set (v:float32<'u>) = this.vector.Y <- v |> float32
                member this.Z
                  with get() = (this.vector.Z |> Float32WithMeasure) : float32<'u>
                  and set (v:float32<'u>) = this.vector.Z <- v |> float32

                override this.ToString() = this.vector.ToString()

                new(x: float32<'u>, y: float32<'u>,z: float32<'u>) = { vector = Microsoft.Xna.Framework.Vector3(x |> float32, y |> float32,z |> float32) }
                new(v: float32<'u>) = { vector = Microsoft.Xna.Framework.Vector3(v |> float32, v |> float32 , v |> float32) }
                private new(v: Microsoft.Xna.Framework.Vector3) = { vector = v }

                static member Zero with get() = Vector3<'u>(Vector3.Zero)
                static member One with get() = Vector3<'u>(Vector3.One)


                static member (+) (v1:Vector3<'u>, v2:Vector3<'u>) = Vector3<'u>(v1.vector + v2.vector)
                static member (+) (v1:Vector3<'u>, f:float32<'u>) = Vector3<'u>(v1.X + f, v1.Y + f ,v1.Z + f)
                static member (-) (v1:Vector3<'u>, v2:Vector3<'u>) = Vector3<'u>(v1.vector - v2.vector)
                static member (-) (v1:Vector3<'u>, f:float32<'u>) = Vector3<'u>(v1.X - f, v1.Y - f ,v1.Z - f)
            
            
            
           end 
           
           type Vector2< [< Measure >] 'u > =
              struct
                val mutable internal vector : Microsoft.Xna.Framework.Vector2

                member this.X 
                  with get() = (this.vector.X |> Float32WithMeasure) : float32<'u>
                  and set (v:float32<'u>) = this.vector.X <- v |> float32
                member this.Y 
                  with get() = (this.vector.Y |> Float32WithMeasure) : float32<'u>
                  and set (v:float32<'u>) = this.vector.Y <- v |> float32

                override this.ToString() = this.vector.ToString()

                new(x: float32<'u>, y: float32<'u>) = { vector = Microsoft.Xna.Framework.Vector2(x |> float32, y |> float32) }
                new(v: float32<'u>) = { vector = Microsoft.Xna.Framework.Vector2(v |> float32, v |> float32) }
                private new(v: Microsoft.Xna.Framework.Vector2) = { vector = v }

                static member Zero with get() = Vector2<'u>(Vector2.Zero)
                static member One with get() = Vector2<'u>(Vector2.One)
                static member UnitX with get() = Vector2<'u>(Vector2.UnitX)
                static member UnitY with get() = Vector2<'u>(Vector2.UnitY)

                static member (+) (v1:Vector2<'u>, v2:Vector2<'u>) = Vector2<'u>(v1.vector + v2.vector)
                static member (+) (v1:Vector2<'u>, f:float32<'u>) = Vector2<'u>(v1.X + f, v1.Y + f)
                static member (-) (v1:Vector2<'u>, v2:Vector2<'u>) = Vector2<'u>(v1.vector - v2.vector)
                static member (-) (v1:Vector2<'u>, f:float32<'u2>) = Vector2<'u>(v1.X - f, v1.Y - f)
                static member (*) (v1:Vector2<'u>, v2:Vector2<'u2>) = Vector2<'u * 'u2>(v1.X * v2.X, v1.Y * v2.Y)
                static member (*) (v1:Vector2<'u>, f:float32<'u2>) = Vector2<'u * 'u2>(v1.vector * (float32 f))
                static member (*) (f:float32<'u2>, v1:Vector2<'u>) = Vector2<'u * 'u2>(v1.vector * (float32 f))
                static member (/) (v1:Vector2<'u>, f:float32<'u2>) = Vector2<'u/'u2>(v1.vector / (float32 f))
                static member (/) (v1:Vector2<'u>, v2:Vector2<'u2>) = Vector2<'u/'u2>(v1.X / v2.X, v1.Y / v2.Y)
                static member (~-) (v:Vector2<'u>) = Vector2<'u>(-v.vector)

                static member inline private lift2 (f:Microsoft.Xna.Framework.Vector2*Microsoft.Xna.Framework.Vector2->'a) (v1:Vector2<'u>, v2:Vector2<'u>) = f(v1.vector,v2.vector)
                static member Dot(v1,v2) = Vector2<'u>.lift2 (Microsoft.Xna.Framework.Vector2.Dot) (v1,v2) |> Float32WithMeasure : float32<'u * 'u>
                static member Distance (v1:Vector2<'u>, v2:Vector2<'u>) = Vector2<'u>.lift2 (Microsoft.Xna.Framework.Vector2.Distance) (v1,v2) |> Float32WithMeasure : float32<'u>
                static member DistanceSquared (v1:Vector2<'u>, v2:Vector2<'u>) = Vector2<'u>.lift2 (Microsoft.Xna.Framework.Vector2.DistanceSquared) (v1,v2) |> Float32WithMeasure : float32<'u * 'u>
                static member Min (m:Vector2<'u>, v:Vector2<'u>) = Vector2<'u>(min m.X v.X, min m.Y v.Y)
                static member Max (m:Vector2<'u>, v:Vector2<'u>) = Vector2<'u>(max m.X v.X, max m.Y v.Y)
                static member Clamp (lower:Vector2<'u>, upper:Vector2<'u>, v:Vector2<'u>) = 
                  let clamp l u v = v |> max l |> min u
                  Vector2<'u>(clamp lower.X upper.X v.X, clamp lower.Y upper.Y v.Y)

                member this.Length() = this.vector.Length() |> Float32WithMeasure : float32<'u>
                member this.LengthSquared() = this.vector.LengthSquared() |> Float32WithMeasure : float32<'u * 'u>
                static member Normalize(v:Vector2<'u>) = Vector2<1>(Vector2.Normalize v.vector)

                //Microsoft.Xna.Framework.Vector2.

      
      end    